package znet

import (
	"errors"
	"fmt"
	"github.com/1141520944/go-library/library/log"
	"go-library/library/goroutine"
	"io"
	"net"
	"sync"
	"zinxLearn/pkg/zinx/util"
	"zinxLearn/pkg/zinx/ziface"
)

type ZConn struct {
	TcpServer    ziface.IServer //当前conn属于哪个server，在conn初始化的时候添加即可
	Conn         *net.TCPConn   // 当前的conn
	ConnID       uint32
	isClosed     bool          // 连接的状态
	ExitChan     chan struct{} // 告诉连接要退出
	l            *log.Logger
	Router       ziface.IMsgHandler     // ziface.IRouter-v0.6 //  该链接处理的router - v0.2 ziface.HandlerFunc
	msgChan      chan []byte            // 用于读、写 两个协程之间的消息通信
	msgBuffChan  chan []byte            // 有关冲管道，用于读、写两个goroutine之间的消息通信
	property     map[string]interface{} // 链接属性
	propertyLock sync.RWMutex           // 保护链接属性修改的锁
}

func (c *ZConn) Start() {
	goroutine.Submit(c.StartReader) // 读协程
	goroutine.Submit(c.StartWriter) // 写协程
	// 这里是否要 for 循环读 -- 测试下来这里不用for循环
	c.TcpServer.CallOnConnStart(c)
}
func (c *ZConn) done() {
	c.ExitChan <- struct{}{}
}
func (c *ZConn) Stop() {
	if c.isClosed { // 已经关闭
		return
	}
	c.isClosed = true
	// todo: 如果用户注册了连接关闭的回调业务
	if err := c.Conn.Close(); err != nil {
		c.l.Errorw("[conn.close]err", err.Error())
	}
	//将链接从连接管理器中删除
	c.TcpServer.GetConnMgr().Remove(c) //删除conn从ConnManager中
	c.done()
	close(c.ExitChan) // 关闭连接的管道
}
func (c *ZConn) GetConnID() uint32 {
	return c.ConnID
}
func (c *ZConn) GetTCPConnection() *net.TCPConn {
	return c.Conn
}
func (c *ZConn) RemoteAddr() net.Addr {
	return c.Conn.RemoteAddr()
}
func NewZConn(l *log.Logger, conn *net.TCPConn, connID uint32, router ziface.IMsgHandler, server ziface.IServer) *ZConn {
	c := &ZConn{
		TcpServer:    server,
		Conn:         conn,
		ConnID:       connID,
		isClosed:     false,
		ExitChan:     make(chan struct{}, 1),
		Router:       router,
		l:            l,
		msgChan:      make(chan []byte), // 消息通信
		msgBuffChan:  make(chan []byte, util.MaxMsgChanLen),
		property:     make(map[string]interface{}),
		propertyLock: sync.RWMutex{},
	}
	c.TcpServer.GetConnMgr().Add(c) //将新创建的Conn添加到链接管理中
	return c
}

func (c *ZConn) StartReader() {
	c.l.Infow("[conn.read(goroutine)]", "running")
	defer c.l.Infow("[conn.read(goroutine)]", "exit ！！！")
	defer c.Stop()
	for {
		dp := NewDataPack() // 拆包装包对象 tlv
		headData := make([]byte, dp.GetHeadLen())
		if _, err := io.ReadFull(c.GetTCPConnection(), headData); err != nil { // 获取客户端的head
			c.l.Errorw("[conn.read].head err", err.Error())
			c.done()
			break
		}
		msg, err := dp.UnPack(headData)
		if err != nil {
			c.l.Errorw("[conn.read].db.UnPack err", err.Error())
			c.done()
			break
		}
		var data []byte // 解析data
		if msg.GetDataLen() > 0 {
			data = make([]byte, msg.GetDataLen()) // 获得客户端的消息
			if _, err = io.ReadFull(c.GetTCPConnection(), data); err != nil {
				c.l.Errorw("[conn.read].body err", err.Error())
				c.done()
				break
			}
		}
		msg.SetData(data) // 设置Data
		req := &ZRequest{ // 请求的Request
			conn: c,
			msg:  msg,
		}
		if c.Router.Size() > 0 {
			c.Router.SendMsgToTaskQueue(req) // 使用工作池
		} else {
			go c.Router.Do(req)
		}
		//go c.Router.Do(req) // 执行路由 v0.6

		//go func(req ziface.IRequest) { // 执行路由 v0.3
		//	defer func() {
		//		if cErr := recover(); cErr != nil {
		//			c.done()
		//		}
		//	}()
		//	c.Router.PreHandle(req)
		//	c.Router.Handle(req)
		//	c.Router.PostHandle(req)
		//}(req)

		// if err = c.handlerAPI(c.Conn, buf, n); err != nil { // 调用业务逻辑  v0.2
		//	c.l.Errorw("[conn.read.handler]err", err.Error())
		//	c.done()
		//	return
		// }
	}
}
func (c *ZConn) StartWriter() {
	c.l.Infow("[conn.write]", "running")
	defer c.l.Infow("[conn.write]", "exited")
	for {
		select {
		case msg, ok := <-c.msgChan:
			if !ok {
				return
			}
			if _, err := c.Conn.Write(msg); err != nil {
				c.l.Errorw("[conn.writer]err", err.Error())
				return
			}
		case msg, ok := <-c.msgBuffChan:
			if !ok {
				return
			}
			if _, err := c.Conn.Write(msg); err != nil {
				fmt.Println("Send Buff Data error:, ", err, " Conn Writer exit")
				return
			} else {
				break
				fmt.Println("msgBuffChan is Closed")
			}
		case <-c.ExitChan:
			//conn已经关闭
			return
		}
	}
}
func (c *ZConn) SendMsg(val ziface.IMessage) error {
	if c.isClosed { // 是否关闭
		return errors.New("[conn]connection closed")
	}
	dp := NewDataPack()
	msg, err := dp.Pack(NewMessage(val.GetMsgID(), val.GetData()))
	if err != nil {
		c.l.Errorw("[conn] SendMsg id", val.GetMsgID())
		return err
	}
	c.msgChan <- msg
	c.l.Infow("conn .write id ", val.GetMsgID())
	return nil
}
func (c *ZConn) SendBuffMsg(msgId uint32, data []byte) error {
	if c.isClosed == true {
		return errors.New("Connection closed when send buff msg")
	}
	//将data封包，并且发送
	dp := NewDataPack()
	msg, err := dp.Pack(NewMessage(msgId, data))
	if err != nil {
		fmt.Println("Pack error msg id = ", msgId)
		return errors.New("Pack error msg ")
	}

	//写回客户端
	c.msgBuffChan <- msg

	return nil
}

// 设置链接属性
func (c *ZConn) SetProperty(key string, value interface{}) {
	c.propertyLock.Lock()
	defer c.propertyLock.Unlock()

	c.property[key] = value
}

// 获取链接属性
func (c *ZConn) GetProperty(key string) (interface{}, error) {
	c.propertyLock.RLock()
	defer c.propertyLock.RUnlock()

	if value, ok := c.property[key]; ok {
		return value, nil
	} else {
		return nil, errors.New("no property found")
	}
}

// 移除链接属性
func (c *ZConn) RemoveProperty(key string) {
	c.propertyLock.Lock()
	defer c.propertyLock.Unlock()

	delete(c.property, key)
}
